#include "Square.h"


Square::Square() {
	this->posicion = new Point();
	this->lado = -1;

}


Square::~Square() {
	delete(this->posicion);
}


void Square::setLado(int nuevoLado) {
	lado = nuevoLado;
}

int Square::getLado() {
	return lado;
}



//--------------------------------------------------------------------------------
void Square::setSquarePoint(Point V1, int L)
{
  v1 = V1;
  l = L;
 
}


void Square::getSquarePoint(Point& V1,int * L)
{
  V1 = v1;
  *L = l;
  ;
}

void Square::setSquareColor(int R, int G, int B)
{
	
	r = R;
	g = G;
	b = B;
}


void Square:: draw(SDL_Surface *screen)
{
    SDL_Surface * auxSurface;
 	Stage* stage = Stage::getInstance();
	int x = posicion->getX();
	int y = posicion->getY();
	int gr;

	int r = getRColorLinea();
	int g = getGColorLinea();
	int b = getBColorLinea();

	Point* resolution = stage->resolveResolution();
	int screenWidth  = resolution->getX();
	int screenHeight = resolution->getY();

	
	Point point1, point2, point3, point4;

	int posX = this->getPosicion()->getX();
	int posY = this->getPosicion()->getY();
	int desplazo = this->getLado();


	//Grosor de linea, primero se lo pido a la figura.
	int grosor = this->getLineThickness();
	if (grosor == -1) {
	//Si la figura no tiene grosor, se lo pido al stage.
		grosor = stage->resolveLineThickness();
		// Entonces lo levanta del stage y no entra al if que viene.
	}
	if (grosor == -1) {
	//Si ni la figura ni el stage tienen grosor, entonces lo seteo en cero,
		grosor = 0;
	}



	point1.setX(posX-grosor);
	point1.setY(posY-grosor);

	point2.setX(posX+desplazo+grosor);
	point2.setY(posY-grosor);

	point3.setX(posX+desplazo+grosor);
	point3.setY(posY+desplazo+grosor);

	point4.setX(posX-grosor);
	point4.setY(posY+desplazo+grosor);

	if (!isInDisplay(&point1,&point2,&point3,&point4)) {
		printf ("%s","**WARNING** La figura no se graficarÃ¡, ya que se encuentra fuera del display.\n");
		return;
	}

//	auxSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, screenWidth, screenHeight,Stage::PIXEL_THICKNESS,rBkDefault, gBkDefault, bBkDefault, 0);

	   auxSurface = manager.createSurface(screenWidth,screenHeight,Stage::PIXEL_THICKNESS);

	//Obetner el color de linea en cascada
	int rl = (this->getRColorLinea() != -1)? this->getRColorLinea() : stage->resolveLineRColor();
	int gl = (this->getGColorLinea() != -1)? this->getGColorLinea() : stage->resolveLineGColor();
	int bl = (this->getBColorLinea() != -1)? this->getBColorLinea() : stage->resolveLineBColor();
	manager.solveFilterColor(rl,gl,&bl);
	manager.setColor(auxSurface,rl,gl,bl);
	
    gr = 0;
    initManagerElement(gr);


	if ( (this->getIdTextura()) != NULL )
	{
		drawTexture(auxSurface);
    }
	else
	{
		fillColor(auxSurface);	
	}

/* Esto era el código original, lo comento porque lo bajé a la fillThickness(...), a futuro se podría sacar.
	int thickness = (getLineThickness() != -1) ? getLineThickness() : Stage::getInstance()->resolveLineThickness();
	for ( gr=0 ; gr<thickness ; gr++){
	
        initManagerElement(gr);

		for (i = 0; i < 4; i++)
		{

			setManagerElement(auxSurface,i);
		}
    
	}  
*/

 	//Obtener el grosor de linea en cascada.
	int thickness = (getLineThickness() != -1) ? getLineThickness() : Stage::getInstance()->resolveLineThickness();
	//Pintamos el grosor de línea.
	this->fillThickness(auxSurface,thickness);

	manager.refresh(screen,auxSurface); // copia la imagen resultante a la pantalla y libera recursos	
	
	
	



}


void Square:: drawTexture(SDL_Surface *auxSurface)
{

	SDL_Surface * imagen;
	Transformations T;
    
	int x = posicion->getX();
	int y = posicion->getY();
    
	Stage* stage = Stage::getInstance();

    imagen = SDL_LoadBMP(stage->getTexturePath( this->getIdTextura()  ));  

   
	T.setScaleMatrix((double)lado/(double)imagen->w,(double)lado/(double)imagen->h); // reduccion 

	SDL_LockSurface(imagen);

	manager.resizeImage(imagen,auxSurface,x,y,lado,lado,T);

	SDL_UnlockSurface(imagen);
   
    SDL_FreeSurface(imagen);


}



void Square::initManagerElement(int gr)
{
  
	int x = posicion->getX();
	int y = posicion->getY();


	e[0].x0 = x - gr;   
	e[0].y0 = y - gr;
	e[0].x1 = x+lado+gr;
	e[0].y1 = y  - gr;   

	e[1].x0 = x+lado + gr;
	e[1].y0 = y-gr;
	e[1].x1 = x+lado+gr ;
	e[1].y1 = y+lado+gr;

	e[2].x0 = x+lado+gr;
	e[2].y0 = y+lado+gr;
	e[2].x1 = x-gr;
	e[2].y1 = y+lado+gr;

	e[3].x0 = x-gr;  
	e[3].y0 = y+lado+gr;
	e[3].x1 = x-gr;
	e[3].y1 = y-gr;

}

void Square::setManagerElement(SDL_Surface * auxSurface, int i)
{

		  e[i].dx = e[i].x1 - e[i].x0;
		  e[i].dy = e[i].y1 - e[i].y0;
		  e[i].ix = 2 * e[i].dx;
		  e[i].iy = 2 * e[i].dy;

		  if (e[i].dx < e[i].dy) 
			{
	  		  manager.swapPoints(&e[i]);
			  e[i].dx = -e[i].dx;
			  e[i].dy = -e[i].dy;
			  e[i].ix = -e[i].ix;
			  e[i].iy = -e[i].iy;
			}
    
		  if ( (e[i].dy <= -e[i].dx) || (e[i].dx < 0) ) manager.bhmLine3_5(auxSurface,&e[i]);
		  else manager.bhmLine1_7(auxSurface,&e[i]);
}



void Square::setPosicion(Point* point) {
	this->posicion->setX(point->getX());
	this->posicion->setY(point->getY());
}

Point* Square::getPosicion() {
	return this->posicion;
}



void Square::hydrate(Element* elem) {
	char* idValue = NULL;
	int ladoValue = -1;
	Point* posicionPoint = new Point();
	int rCLValue = -1;
	int gCLValue = -1;
	int bCLValue = -1;
	int rCFValue = -1;
	int gCFValue = -1;
	int bCFValue = -1;
	int lineThickness = -1;
	char* texId = NULL;
	Element auxElem;
	Attr auxAttr;
	int i=0;
	int j;


	//extraigo los subElementos con todos sus valores
	while(vectorListGetItem(elem->elems,i,&auxElem) != -1) {
		//Posicion
		if( strcmp("posicion", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("x", auxAttr.name) == 0 )
					posicionPoint->setX(atoi(auxAttr.value));
				if(strcmp("y", auxAttr.name) == 0 )
					posicionPoint->setY(atoi(auxAttr.value));
				j++;
			}
		}

		//Colorlinea
		if( strcmp("colorlinea", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("r", auxAttr.name) == 0 )
					rCLValue = atoi(auxAttr.value);
				if(strcmp("g", auxAttr.name) == 0 )
					gCLValue = atoi(auxAttr.value);
				if(strcmp("b", auxAttr.name) == 0 )
					bCLValue = atoi(auxAttr.value);
				j++;
			}
		}

		//ColorFigura
		if( strcmp("colorfigura", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("r", auxAttr.name) == 0 )
					rCFValue = atoi(auxAttr.value);
				if(strcmp("g", auxAttr.name) == 0 )
					gCFValue = atoi(auxAttr.value);
				if(strcmp("b", auxAttr.name) == 0 )
					bCFValue = atoi(auxAttr.value);
				j++;
			}
		}

		//LineThickness
		if( strcmp("grosorlinea", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("valor", auxAttr.name) == 0 )
					lineThickness = atoi(auxAttr.value);
				
				j++;
			}
		}

		//textura
		if( strcmp("textura", auxElem.name) == 0 ) {
			j=0;
			while(vectorListGetItem(auxElem.attrs,j,&auxAttr) != -1) {
				if(strcmp("id", auxAttr.name) == 0 )
					texId = auxAttr.value;
				j++;
			}
		}
		i++;
	}

	i=0;
	
	//extraigo los valores de los atributos de circulo
	while(vectorListGetItem(elem->attrs,i,&auxAttr) != -1) {
		if(strcmp("id", auxAttr.name) == 0 )
			idValue = auxAttr.value;
		if(strcmp("lado", auxAttr.name) == 0 )
			ladoValue = atoi(auxAttr.value);
		i++;
	}

	this->setId(idValue);
	this->setLado(ladoValue);
	this->setPosicion(posicionPoint);
	this->setRColorLinea(rCLValue);
	this->setGColorLinea(gCLValue);
	this->setBColorLinea(bCLValue);
	this->setRColorFigura(rCFValue);
	this->setGColorFigura(gCFValue);
	this->setBColorFigura(bCFValue);
	this->setIdTextura(texId);
	this->setLineThickness(lineThickness);

}


int Square::serialize(Element* elem) {
	Element posicion;
	Element colorlinea;
	Element colorfigura;
	Element textura;
	Attr attId;
	Attr attLado;
	Attr attX;
	Attr attY;
	Attr attRColorLinea;
	Attr attBColorLinea;
	Attr attGColorLinea;
	Attr attRColorFigura;
	Attr attGColorFigura;
	Attr attBColorFigura;
	Attr attIdTextura;

	//INICIO: inicializamos elementos y atributos.
	initAtt(&attId,255);
	initAtt(&attLado,255);
	initAtt(&attX,255);
	initAtt(&attY,255);
	initAtt(&attRColorLinea,255);
	initAtt(&attGColorLinea,255);
	initAtt(&attBColorLinea,255);
	initAtt(&attRColorFigura,255);
	initAtt(&attGColorFigura,255);
	initAtt(&attBColorFigura,255);
	initAtt(&attIdTextura,255);
	initElement(&(*elem),255,255);
	initElement(&posicion,255,255);
	initElement(&colorlinea,255,255);
	initElement(&colorfigura,255,255);
	initElement(&textura,255,255);
	//FIN: inicializamos elementos y atributos.

	//INICIO: cargamos los nombres de los elementos.
	memset(elem->name,'\0',255);
	elem->name = "cuadrado";
	memset(posicion.name,'\0',255);
	posicion.name = "posicion";
	memset(colorlinea.name,'\0',255);
	colorlinea.name = "colorlinea";
	memset(colorfigura.name,'\0',255);
	colorfigura.name = "colorfigura";
	memset(textura.name,'\0',255);
	textura.name = "textura";
	//FIN: cargamos los nombres de los elementos.


	//INICIO: cargamos atributos de CIRCULO.
	memset(attId.name,'\0',255);
	attId.name = "id";
	memset(attId.value,'\0',255);
	attId.value = this->getId();

	vectorListAddItem(&(elem->attrs),&attId,sizeof(attId));

	memset(attLado.name,'\0',255);
	attLado.name = "lado";
	memset(attLado.value,'\0',255);
	string lado = intToString(this->getLado());
	const char* ladoChar = lado.c_str();
	strcpy(attLado.value,ladoChar);

	vectorListAddItem(&(elem->attrs),&attLado,sizeof(attLado));
	//FIN: cargamos atributos de CIRCULO.



	//INICIO: cargamos atributos de POSICION.
	memset(attX.name,'\0',255);
	attX.name = "x";
	memset(attX.value,'\0',255);
	string xString = intToString(this->getPosicion()->getX());
	const char* xChar = xString.c_str(); 
	strcpy(attX.value,xChar);

	vectorListAddItem(&(posicion.attrs),&attX,sizeof(attX));

	memset(attY.name,'\0',255);
	attY.name = "y";
	memset(attY.value,'\0',255);
	string yString = intToString(this->getPosicion()->getY());
	const char* yChar = yString.c_str(); 
	strcpy(attY.value,yChar);

	vectorListAddItem(&(posicion.attrs),&attY,sizeof(attY));
	//FIN: cargamos atributos de POSICION.


	//INICIO: cargamos atributos de COLORLINEA.
	memset(attRColorLinea.name,'\0',255);
	attRColorLinea.name = "r";
	memset(attRColorLinea.value,'\0',255);
	string rColorLineaString = intToString(this->getRColorLinea());
	const char* rCLChar = rColorLineaString.c_str();
	strcpy(attRColorLinea.value,rCLChar);

	vectorListAddItem(&(colorlinea.attrs),&attRColorLinea,sizeof(attRColorLinea));

	memset(attGColorLinea.name,'\0',255);
	attGColorLinea.name = "g";
	memset(attGColorLinea.value,'\0',255);
	string gColorLineaString = intToString(this->getGColorLinea());
	const char* gCLChar = gColorLineaString.c_str();
	strcpy(attGColorLinea.value,gCLChar);

	vectorListAddItem(&(colorlinea.attrs),&attGColorLinea,sizeof(attGColorLinea));

	memset(attBColorLinea.name,'\0',255);
	attBColorLinea.name = "b";
	memset(attBColorLinea.value,'\0',255);
	string bColorLineaString = intToString(this->getBColorLinea());
	const char* bCLChar = bColorLineaString.c_str();
	strcpy(attBColorLinea.value,bCLChar);

	vectorListAddItem(&(colorlinea.attrs),&attBColorLinea,sizeof(attBColorLinea));
	//FIN: cargamos atributos de COLORLINEA.


	//INICIO: cargamos atributos de COLORFIGURA.
	memset(attRColorFigura.name,'\0',255);
	attRColorFigura.name = "r";
	memset(attRColorFigura.value,'\0',255);
	string rColorFiguraString = intToString(this->getRColorFigura());
	const char* rCFChar = rColorFiguraString.c_str();
	strcpy(attRColorFigura.value,rCFChar);

	vectorListAddItem(&(colorfigura.attrs),&attRColorFigura,sizeof(attRColorFigura));

	memset(attGColorFigura.name,'\0',255);
	attGColorFigura.name = "g";
	memset(attGColorFigura.value,'\0',255);
	string gColorFiguraString = intToString(this->getGColorFigura());
	const char* gCFChar = gColorFiguraString.c_str();
	strcpy(attGColorFigura.value,gCFChar);

	vectorListAddItem(&(colorfigura.attrs),&attGColorFigura,sizeof(attGColorFigura));

	memset(attBColorFigura.name,'\0',255);
	attBColorFigura.name = "b";
	memset(attBColorFigura.value,'\0',255);
	string bColorFiguraString = intToString(this->getBColorFigura());
	const char* bCFChar = bColorFiguraString.c_str();
	strcpy(attBColorFigura.value,bCFChar);

	
	vectorListAddItem(&(colorfigura.attrs),&attBColorFigura,sizeof(attBColorFigura));
	//FIN: cargamos atributos de COLORFIGURA.


	//INICIO: cargamos atributos de TEXTURA.	
	memset(attIdTextura.name,'\0',255);
	attIdTextura.name = "id";
	memset(attIdTextura.value,'\0',255);
	attIdTextura.value = this->getIdTextura();

	vectorListAddItem(&(textura.attrs),&attIdTextura,sizeof(attIdTextura));

	//FIN: cargamos atributos de TEXTURA.


	//INICIO: agregamos todos los elementos dentro de la figura.
	vectorListAddItem(&(elem->elems),&posicion,sizeof(posicion));
	vectorListAddItem(&(elem->elems),&colorlinea,sizeof(colorlinea));
	vectorListAddItem(&(elem->elems),&colorfigura,sizeof(colorfigura));
	vectorListAddItem(&(elem->elems),&textura,sizeof(textura));
	//FIN: agregamos todos los elementos dentro de la figura.
	

	return 0;

}


void Square::fillColor(SDL_Surface *screen) {


	SDLDrawElement eAux;
	manager.bhmScanLineInit(screen,&eAux);

	for ( int i= 0; i < 4; i++) {
		manager.bhmScanLine(screen,e[i].x0,e[i].y0,e[i].x1,e[i].y1,&eAux);	
	}
	// ahora unimos el primer y el ultimo  punto
	//manager.bhmScanLine(screen,e[3].x0,e[3].y0,e[0].x1,e[0].y1,&eAux);	

	//Obetner el color de Figura en cascada
	Stage* stage = Stage::getInstance();
	int r = (this->getRColorFigura() != -1)? this->getRColorFigura() : stage->resolveShapeRColor();
	int g = (this->getGColorFigura() != -1)? this->getGColorFigura() : stage->resolveShapeGColor();
	int b = (this->getBColorFigura() != -1)? this->getBColorFigura() : stage->resolveShapeBColor();

	manager.setColor(screen,r,g,b);

	manager.bhmScanLineFill(screen,&eAux); // ESTE RELLENA ADENTRO

	//Obetner el color de linea en cascada
	int rl = (this->getRColorLinea() != -1)? this->getRColorLinea() : stage->resolveLineRColor();
	int gl = (this->getGColorLinea() != -1)? this->getGColorLinea() : stage->resolveLineGColor();
	int bl = (this->getBColorLinea() != -1)? this->getBColorLinea() : stage->resolveLineBColor();

	manager.setColor(screen,rl,gl,bl);


 }




void Square::fillThickness(SDL_Surface *screen, int thickness) {
	Stage* stage = Stage::getInstance();
	for ( int gr=0 ; gr<thickness ; gr++) {
        initManagerElement(gr);
		for (int i = 0; i < 4; i++) {
			setManagerElement(screen,i);
		}
	}  
}
